package com.nineclock.sign.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.DateTimeUtil;
import com.nineclock.sign.dto.SignInfoDTO;
import com.nineclock.sign.dto.SignPCListDTO;
import com.nineclock.sign.mapper.SignMapper;
import com.nineclock.sign.pojo.SignInfo;
import com.nineclock.sign.service.SignService;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.dto.SysDepartmentDTO;
import com.nineclock.system.feign.SysUserFeign;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SignServiceImpl implements SignService {
    @Autowired
    private SignMapper signMapper;
    @Autowired
    private SysUserFeign sysUserFeign;

    public PageResult<List<SignPCListDTO>> querySignData(String startTime, String endTime, Integer page, Integer pageSize) {
        List<SignPCListDTO> resultList = new ArrayList<>();
        //获取时间集合
        List<String> dateStr = DateTimeUtil.getDatesBetweenTwoDate(startTime, endTime, "yyyy-MM-dd").stream().map(date -> {
            return DateTimeUtil.dateToStr(date).substring(0, 10);
        }).collect(Collectors.toList());
        //构建查询条件

        LambdaQueryWrapper<SignInfo> signInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        signInfoLambdaQueryWrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        signInfoLambdaQueryWrapper.in(SignInfo::getCreateDate, dateStr);
        List<SignInfo> infos = signMapper.selectList(signInfoLambdaQueryWrapper);
        if (CollectionUtil.isNotEmpty(infos)) {
            List<Long> companyUserIdList = infos.stream().map(info -> {
                return info.getCompanyUserId();
            }).collect(Collectors.toList());
            List<Long> companyUserIds = CollectionUtil.distinct(companyUserIdList);
            long total = companyUserIds.size();
            long pages = (long) Math.ceil(total * 1.0 / pageSize);


            //根据员工id分组
            Map<Long, List<SignInfo>> map = infos.stream().collect(Collectors.groupingBy(SignInfo::getCompanyUserId));
            for (int i = (page - 1) * pageSize; i < (total < pageSize * page ? total : pageSize * page); i++) {
                Long companyUserId = companyUserIds.get(i);
                //查询员工数据
                SysCompanyUserDTO companyUserDTO = sysUserFeign.queryCompanyUserById(companyUserId).getData();
                SignPCListDTO signPCListDTO = BeanHelper.copyProperties(companyUserDTO, SignPCListDTO.class);
                signPCListDTO.setUsername(companyUserDTO.getUserName());

                //设置部门信息
                SysDepartmentDTO sysDepartmentDTO = new SysDepartmentDTO();
                sysDepartmentDTO.setId(companyUserDTO.getDepartmentId());
                sysDepartmentDTO.setName(companyUserDTO.getDepartmentName());
                signPCListDTO.setDepartment(sysDepartmentDTO);
                //获取该员工的签到数据
                List<SignInfo> signInfos = map.get(companyUserId);
                //根据签到时间分组
                Map<String, List<SignInfo>> mapDate = signInfos.stream().collect(Collectors.groupingBy(SignInfo::getCreateDate));
                //设置签到信息
                List<SignInfoDTO> signs = new ArrayList<>();
                for (String date : dateStr) {
                    SignInfoDTO signInfoDTO = new SignInfoDTO();
                    List<SignInfo> infoList = mapDate.get(date);
                    if (CollectionUtil.isNotEmpty(infoList)) {
                        signInfoDTO.setSignCount(infoList.size());
                    } else {
                        signInfoDTO.setSignCount(0);
                    }
                    signInfoDTO.setSignDate(date);
                    signs.add(signInfoDTO);
                }
                signPCListDTO.setSigns(signs);
                resultList.add(signPCListDTO);
            }

            return new PageResult(total, pages, resultList);
        }
        return new PageResult();
    }


    /**
     * 导出签到列表
     *
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public void exportData(String startTime, String endTime) throws IOException {
        //List<SignPCListDTO> signPCListDTOList = this.querySignData(startTime,endTime);
        //获取时间列表
        List<Date> dateList = DateTimeUtil.getDatesBetweenTwoDate(startTime, endTime, "yyyy-MM-dd");
        List<String> dateStr = dateList.stream().map(date -> {
            return DateTimeUtil.dateToStr(date);
        }).collect(Collectors.toList());

        //设置文件下载的头信息
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.setHeader("Content-disposition", "attachment;filename=Attendance.xlsx ");
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setCharacterEncoding("utf-8");

        WriteCellStyle cellStyle = new WriteCellStyle();
        //表头和内容都是水平居中
        cellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        //设置字体
        WriteFont font = new WriteFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 14);
        cellStyle.setWriteFont(font);

        HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(cellStyle, cellStyle);

        EasyExcel.write(response.getOutputStream())
                .excelType(ExcelTypeEnum.XLSX)
                .head(header(dateStr))
                .registerWriteHandler(styleStrategy)
                .registerWriteHandler(new MyColumnStyle());
        //.sheet("签到数据").doWrite(data(signPCListDTOList));

    }

    /**
     * 获取动态表头信息
     *
     * @param dateStr
     * @return
     */
    public List<List<String>> header(List<String> dateStr) {
        List<List<String>> resultList = new ArrayList<>();
        resultList.add(Arrays.asList("姓名"));
        resultList.add(Arrays.asList("工号"));
        resultList.add(Arrays.asList("部门"));
        resultList.add(Arrays.asList("职位"));
        if (CollectionUtil.isNotEmpty(dateStr)) {
            for (String s : dateStr) {
                resultList.add(Arrays.asList(s));
            }
        }
        return resultList;
    }

    /**
     * 组装表格数据
     *
     * @param signPCListDTOs
     * @return
     */
    public List<List<String>> data(List<SignPCListDTO> signPCListDTOs) {
        List<List<String>> data = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(signPCListDTOs)) {
            for (SignPCListDTO signPCListDTO : signPCListDTOs) {
                List<String> list = new ArrayList<>();
                list.add(signPCListDTO.getUsername());
                list.add(signPCListDTO.getWorkNumber());
                list.add(signPCListDTO.getDepartment().getName());
                list.add(signPCListDTO.getPost());
                //获取打卡数据
                List<SignInfoDTO> signs = signPCListDTO.getSigns();
                if (CollectionUtil.isNotEmpty(signs)) {
                    for (SignInfoDTO sign : signs) {
                        list.add(sign.getSignCount() + "");
                    }
                }
            }
        }
        return data;
    }

    /**
     * 内部类。设置文件单元格宽度
     */
    static class MyColumnStyle extends AbstractColumnWidthStyleStrategy {
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList,
                                      Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
            //改变 单元格 宽度
            writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 4500);
        }
    }
}
